import React, { createContext, useContext, useEffect, useState } from 'react';
import { ethers } from 'ethers';
import Web3Modal from 'web3modal';
import WalletConnectProvider from '@walletconnect/web3-provider';
import toast from 'react-hot-toast';

const WalletContext = createContext();

export const useWallet = () => {
  const context = useContext(WalletContext);
  if (!context) {
    throw new Error('useWallet must be used within a WalletProvider');
  }
  return context;
};

export const WalletProvider = ({ children }) => {
  const [account, setAccount] = useState(null);
  const [provider, setProvider] = useState(null);
  const [chainId, setChainId] = useState(null);
  const [isConnecting, setIsConnecting] = useState(false);
  const [web3Modal, setWeb3Modal] = useState(null);

  const BSC_MAINNET = {
    chainId: '0x38', // 56 in hex
    chainName: 'Binance Smart Chain Mainnet',
    nativeCurrency: {
      name: 'BNB',
      symbol: 'BNB',
      decimals: 18,
    },
    rpcUrls: ['https://bsc-dataseed1.binance.org/'],
    blockExplorerUrls: ['https://bscscan.com/'],
  };

  const BSC_TESTNET = {
    chainId: '0x61', // 97 in hex
    chainName: 'Binance Smart Chain Testnet',
    nativeCurrency: {
      name: 'BNB',
      symbol: 'BNB',
      decimals: 18,
    },
    rpcUrls: ['https://data-seed-prebsc-1-s1.binance.org:8545/'],
    blockExplorerUrls: ['https://testnet.bscscan.com/'],
  };

  useEffect(() => {
    if (typeof window !== 'undefined') {
      const providerOptions = {
        walletconnect: {
          package: WalletConnectProvider,
          options: {
            rpc: {
              56: 'https://bsc-dataseed1.binance.org/',
              97: 'https://data-seed-prebsc-1-s1.binance.org:8545/',
            },
            network: 'binance',
            chainId: 56,
          },
        },
      };

      const modal = new Web3Modal({
        cacheProvider: true,
        providerOptions,
        theme: 'dark',
      });

      setWeb3Modal(modal);

      if (modal.cachedProvider) {
        connectWallet();
      }
    }
  }, []);

  const connectWallet = async () => {
    if (!web3Modal) return;

    try {
      setIsConnecting(true);

      const instance = await web3Modal.connect();
      const provider = new ethers.providers.Web3Provider(instance);
      const signer = provider.getSigner();
      const address = await signer.getAddress();
      const network = await provider.getNetwork();

      setProvider(provider);
      setAccount(address);
      setChainId(network.chainId);

      // Check if we're on the correct network
      if (network.chainId !== 56 && network.chainId !== 97) {
        toast.error('Please connect to Binance Smart Chain');
        await switchToBSC();
      }

      // Subscribe to accounts change
      instance.on('accountsChanged', (accounts) => {
        if (accounts.length > 0) {
          setAccount(accounts[0]);
        } else {
          disconnectWallet();
        }
      });

      // Subscribe to chain change
      instance.on('chainChanged', (chainId) => {
        setChainId(parseInt(chainId, 16));
        window.location.reload();
      });

      // Subscribe to provider disconnection
      instance.on('disconnect', () => {
        disconnectWallet();
      });

      toast.success('Wallet connected successfully');
    } catch (error) {
      console.error('Wallet connection error:', error);
      toast.error('Failed to connect wallet');
    } finally {
      setIsConnecting(false);
    }
  };

  const disconnectWallet = async () => {
    if (web3Modal) {
      await web3Modal.clearCachedProvider();
    }
    setAccount(null);
    setProvider(null);
    setChainId(null);
    toast.success('Wallet disconnected');
  };

  const switchToBSC = async () => {
    if (!provider) return;

    try {
      await provider.provider.request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: BSC_MAINNET.chainId }],
      });
    } catch (switchError) {
      // This error code indicates that the chain has not been added to MetaMask
      if (switchError.code === 4902) {
        try {
          await provider.provider.request({
            method: 'wallet_addEthereumChain',
            params: [BSC_MAINNET],
          });
        } catch (addError) {
          console.error('Error adding BSC network:', addError);
          toast.error('Failed to add BSC network');
        }
      } else {
        console.error('Error switching to BSC:', switchError);
        toast.error('Failed to switch to BSC network');
      }
    }
  };

  const signMessage = async (message) => {
    if (!provider) {
      throw new Error('Wallet not connected');
    }

    try {
      const signer = provider.getSigner();
      const signature = await signer.signMessage(message);
      return signature;
    } catch (error) {
      console.error('Error signing message:', error);
      throw new Error('Failed to sign message');
    }
  };

  const sendTransaction = async (to, value, data = '0x') => {
    if (!provider) {
      throw new Error('Wallet not connected');
    }

    try {
      const signer = provider.getSigner();
      const transaction = {
        to,
        value,
        data,
      };

      const tx = await signer.sendTransaction(transaction);
      return tx;
    } catch (error) {
      console.error('Error sending transaction:', error);
      throw new Error('Failed to send transaction');
    }
  };

  const isCorrectNetwork = () => {
    return chainId === 56 || chainId === 97;
  };

  const getNetworkName = () => {
    switch (chainId) {
      case 56:
        return 'BSC Mainnet';
      case 97:
        return 'BSC Testnet';
      default:
        return 'Unknown Network';
    }
  };

  const value = {
    account,
    provider,
    chainId,
    isConnecting,
    isCorrectNetwork: isCorrectNetwork(),
    networkName: getNetworkName(),
    connectWallet,
    disconnectWallet,
    switchToBSC,
    signMessage,
    sendTransaction,
    BSC_MAINNET,
    BSC_TESTNET,
  };

  return (
    <WalletContext.Provider value={value}>
      {children}
    </WalletContext.Provider>
  );
};